package com.apobates.forum.toro.template;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
/**
 * 聚合属性构建器
 * 适用于: 构造的对象(target.OrdersVo)包含有查询对象(select.Orders)的属性(表达式中汲及的属性需要存在)
 * @param <E> 最终结果的类型
 *
 * @author xiaofanku@live.cn
 * @since 20220517
 */
public class TemplateMapper<E> {
    private static final Logger logger = LoggerFactory.getLogger(TemplateMapper.class);
    /**
     * 目标对象Class
     * 例: OrdersVo.class
     */
    private final Class<E> className;

    /**
     * TemplateMapper构造函数
     *
     * @param className 目标对象Class. 例: OrdersVo.class
     */
    private TemplateMapper(Class<E> className) {
        this.className = className;
    }

    /**
     * 设置模板对象Class. 通常是包含查询对象属性的类
     *
     * @param className 目标对象Class. 例: OrdersVo.class
     * @return 聚合属性构建器
     * @param <E> 目标对象类型
     */
    public static <E> TemplateMapper template(Class<E> className) {
        return new TemplateMapper(className);
    }

    /**
     * 返回基础属性语句
     * @param tag 标签名，用于分组不同的聚合字段属于哪个类
     * @param joinAttrName 选择对象的类名的连接属性 Orders.memberId( = Member.id)
     * @return
     */
    public TemplateStatements one(String tag, String joinAttrName) {
        return new TemplateStatements(tag, joinAttrName);
    }

    /**
     * 返回批量属性语句
     * @param tag 标签名，用于分组不同的聚合字段属于哪个类
     * @param joinAttrName 选择对象的类名的连接属性，例:memberId; Orders.memberId( = Member.id)
     * @param linkAttrName 命中对象集合中元素的连接属性，例:id; on Orders.memberId = Member.id
     * @return
     */
    public TemplateStatements many(String tag, String joinAttrName, String linkAttrName) {
        return new TemplateStatements(tag, joinAttrName, linkAttrName);
    }

    /**
     * 一对一模式(one to one)
     * 例: 一张订单的购买者和商品的聚合
     * 适用于: 已知起始对象实例
     *
     * @param selectObj 查询对象实例. 例: Orders
     * @param isConcurrent 是否并发执行;true并发,false串行
     * @return
     * @param <T> 基对象的类型
     */
    public <T> TemplateMapperExecutor<E,T> by(T selectObj, boolean isConcurrent){
        final Collection<T> args = Collections.unmodifiableList(List.of(selectObj));
        return new TemplateMapperExecutor(()->args, this.className, isConcurrent, false);
    }

    /**
     * 一对一模式(one to one)
     * 例: 一张订单的购买者和商品的聚合
     * 适用于: 起始对象实例不确定时
     *
     * @param selectObjSup 起始对象供应函.
     * @param isConcurrent 是否并发执行;true并发,false串行
     * @return
     * @param <T> 基对象的类型
     */
    public <T> TemplateMapperExecutor<E,T> supplyOne(Supplier<T> selectObjSup, boolean isConcurrent){
        final Collection<T> args = Collections.unmodifiableList(List.of(selectObjSup.get()));
        return new TemplateMapperExecutor(()->args, this.className, isConcurrent, false);
    }

    /**
     * 多对多模式(many to many)
     * 例: 不同人购买不同商品的订单聚合
     * 适用于: 已知起始对象实例
     *
     * @param selectObjSet 查询对象实例集合. 例: Set<Orders>
     * @param isConcurrent 是否并发执行;true并发,false串行
     * @return
     * @param <T> 基对象的类型
     */
    public <T> TemplateMapperExecutor<E,T> by(Collection<T> selectObjSet, boolean isConcurrent){
        final Collection<T> args = Collections.unmodifiableCollection(selectObjSet);
        return new TemplateMapperExecutor(()->args, this.className, isConcurrent, true);
    }

    /**
     * 多对多模式(many to many)
     * 例: 不同人购买不同商品的订单聚合
     * 适用于: 起始对象实例不确定时
     *
     * @param selectObjSetSup 起始对象供应函.
     * @param isConcurrent 是否并发执行;true并发,false串行
     * @return
     * @param <T> 基对象的类型
     */
    public <T> TemplateMapperExecutor<E,T> supplyMany(Supplier<Collection<T>> selectObjSetSup, boolean isConcurrent){
        return new TemplateMapperExecutor(selectObjSetSup, this.className, isConcurrent, true);
    }
}
